package com.luxondata.security;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;

import com.luxondata.exception.MissingApiKeyException;

@Component
@ServletComponentScan
@WebFilter(urlPatterns = "/api/**",filterName = "apiKeyAuthenticationProcessingFilter")
public class ApiKeyAuthenticationProcessingFilter implements Filter{
	
	private static Logger logger = LoggerFactory.getLogger(ApiKeyAuthenticationProcessingFilter.class);

	/** ApiKey验证管理器 */
	@Autowired
	private AuthenticationManager authenticationManager;
	/** ApiKey验证错误处理入口 */
	@Autowired
	private AuthenticationEntryPoint authenticationEntryPoint;
	
	public void setAuthenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
		this.authenticationEntryPoint = authenticationEntryPoint;
	}

	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}


	@Override
	public void destroy() {
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
		final HttpServletRequest request = (HttpServletRequest) req;
		final HttpServletResponse response = (HttpServletResponse) res;
		// 若还没有认证通过
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		
		try {

			if (authentication==null || authentication.isAuthenticated()){
				String apiKey = request.getHeader("apiKey");
				if (StringUtils.isBlank(apiKey)) {
					logger.debug("No api key supplied, continue the chain");
					throw new MissingApiKeyException("No api key provided");
				} else {
					authentication = new PreAuthenticatedAuthenticationToken(null,apiKey.trim());
					Authentication auth = authenticationManager.authenticate(authentication);
					logger.debug("Authentication success: " + auth);
					SecurityContextHolder.getContext().setAuthentication(auth);
				}
			}
		} catch (AuthenticationException e){
			SecurityContextHolder.clearContext();
			logger.debug("Authentication request failed: " + e);
			authenticationEntryPoint.commence(request, response, e);
			return;
		}
		chain.doFilter(request, response);
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
	}

}
